package com.atguigu.yygh.hosp.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.yygh.hosp.repository.ScheduleRepository;
import com.atguigu.yygh.hosp.service.DepartmentService;
import com.atguigu.yygh.hosp.service.HospitalService;
import com.atguigu.yygh.hosp.service.ScheduleService;
import com.atguigu.yygh.model.hosp.Schedule;
import com.atguigu.yygh.vo.hosp.BookingScheduleRuleVo;
import com.atguigu.yygh.vo.hosp.ScheduleQueryVo;
import org.joda.time.DateTime;
import org.joda.time.DateTimeConstants;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zfj
 * @date 2024/4/8 -11:17
 */
@Service
public class ScheduleServiceImpl implements ScheduleService {
	@Autowired
	private ScheduleRepository scheduleRepository;

	@Autowired
	private MongoTemplate mongoTemplate;

	@Autowired
	private HospitalService hospitalService;

	@Autowired
	private DepartmentService departmentService;

	@Override
	public void save(Map<String, Object> paramMap) {
		Schedule schedule = JSONObject.parseObject(JSONObject.toJSONString(paramMap), Schedule.class);
		Schedule targetSchedule = scheduleRepository.getScheduleByHoscodeAndHosScheduleId(schedule.getHoscode(), schedule.getHosScheduleId());
		if (null != targetSchedule) {
			BeanUtils.copyProperties(schedule, targetSchedule, Schedule.class);
			scheduleRepository.save(targetSchedule);
		} else {
			schedule.setCreateTime(new Date());
			schedule.setUpdateTime(new Date());
			schedule.setIsDeleted(0);
			scheduleRepository.save(schedule);
		}
	}

	@Override
	public Page<Schedule> selectPage(int page, int limit, ScheduleQueryVo scheduleQueryVo) {
		Sort sort = Sort.by(Sort.Direction.DESC, "createTime");
		// 0为第一页
		Pageable pageable = PageRequest.of(page - 1, limit, sort);

		Schedule schedule = new Schedule();
		BeanUtils.copyProperties(scheduleQueryVo, schedule);
		schedule.setIsDeleted(0);

		// 创建匹配器，即如何使用查询条件
		ExampleMatcher matcher = ExampleMatcher.matching() //构建对象
				.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) //改变默认字符串匹配方式：模糊查询
				.withIgnoreCase(true); //改变默认大小写忽略方式：忽略大小写

		//创建实例
		Example<Schedule> example = Example.of(schedule, matcher);
		return scheduleRepository.findAll(example, pageable);
	}

	@Override
	public void remove(String hoscode, String hosScheduleId) {
		Schedule schedule = scheduleRepository.getScheduleByHoscodeAndHosScheduleId(hoscode, hosScheduleId);
		if (null != schedule) {
			scheduleRepository.deleteById(schedule.getId());
		}
	}

	//根据医院编号和科室编号，查询排班的规则数据
	@Override
	public Map<String, Object> getRuleSchedule(long page, long limit, String hoscode, String depcode) {
		//根据医院编号和科室编号查询
		Criteria criteria=Criteria.where("hoscode").is(hoscode).and("depcode").is(depcode);
		//根据工作日期进行分组
		Aggregation agg= Aggregation.newAggregation(
				Aggregation.match(criteria),//匹配条件
				Aggregation.group("workDate")//分组字段
				.first("workDate").as("workDate")
				//统计号源数量
				.count().as("docCount")
				.sum("reservedNumber").as("reservedNumber")
				.sum("availableNumber").as("availableNumber"),
				//排序
				Aggregation.sort(Sort.Direction.DESC,"workDate"),
				//实现分页
				Aggregation.skip((page-1)*limit),
				Aggregation.limit(limit)
		);
		//调用方法，最后执行
		AggregationResults<BookingScheduleRuleVo> aggResult = mongoTemplate.aggregate(agg, Schedule.class, BookingScheduleRuleVo.class);
		List<BookingScheduleRuleVo> bookingScheduleRuleVoList = aggResult.getMappedResults();

		//分组查询的总记录数
		Aggregation totalAgg= Aggregation.newAggregation(
				Aggregation.match(criteria),//匹配条件
				Aggregation.group("workDate")//分组字段
		);
		AggregationResults<BookingScheduleRuleVo> totalAggResult = mongoTemplate.aggregate(totalAgg, Schedule.class, BookingScheduleRuleVo.class);
		int total = totalAggResult.getMappedResults().size();

		//把日期对应的星期获取
		for(BookingScheduleRuleVo bookingScheduleRuleVo:bookingScheduleRuleVoList){
			Date workDate = bookingScheduleRuleVo.getWorkDate();
			String dayOfWeek = this.getDayOfWeek(new DateTime(workDate));
			bookingScheduleRuleVo.setDayOfWeek(dayOfWeek);

		}
		//设置最终数据，进行返回
		Map<String, Object> result =new HashMap<>();
		result.put("bookingScheduleRuleVoList",bookingScheduleRuleVoList);
		result.put("total",total);

		//获取医院名称
		String hosName = hospitalService.getHospName(hoscode);
		//其他基础数据
		Map<String, String> baseMap = new HashMap<>();
		baseMap.put("hosname", hosName);
		result.put("baseMap", baseMap);

		return result;
	}

	//根据医院编号，科室编号和工作日期查询详细信息
	@Override
	public List<Schedule> getDetailSchedule(String hoscode, String depcode, String workDate) {
		//根据参数查询mongoDB
		List<Schedule> scheduleList =
				scheduleRepository.findScheduleByHoscodeAndDepcodeAndWorkDate(hoscode, depcode, new DateTime(workDate).toDate());
		//list遍历，设置其他参数
		scheduleList.stream().forEach(item->{
			this.packageSchedule(item);
		});
		return scheduleList;
	}

	/**
	 * 封装排班详情其他值 医院名称、科室名称、日期对应星期
	 *
	 * @param schedule
	 * @return
	 */
	private Schedule packageSchedule(Schedule schedule) {
		//设置医院名称
		schedule.getParam().put("hosname", hospitalService.getHospName(schedule.getHoscode()));
		//设置科室名称
		schedule.getParam().put("depname", departmentService.getDepName(schedule.getHoscode(), schedule.getDepcode()));
		//设置日期对应星期
		schedule.getParam().put("dayOfWeek", this.getDayOfWeek(new DateTime(schedule.getWorkDate())));
		return schedule;
	}

	/**
	 * 根据日期获取周几数据
	 *
	 * @param dateTime
	 * @return
	 */
	private String getDayOfWeek(DateTime dateTime) {
		String dayOfWeek = "";
		switch (dateTime.getDayOfWeek()) {
			case DateTimeConstants.SUNDAY:
				dayOfWeek = "周日";
				break;
			case DateTimeConstants.MONDAY:
				dayOfWeek = "周一";
				break;
			case DateTimeConstants.TUESDAY:
				dayOfWeek = "周二";
				break;
			case DateTimeConstants.WEDNESDAY:
				dayOfWeek = "周三";
				break;
			case DateTimeConstants.THURSDAY:
				dayOfWeek = "周四";
				break;
			case DateTimeConstants.FRIDAY:
				dayOfWeek = "周五";
				break;
			case DateTimeConstants.SATURDAY:
				dayOfWeek = "周六";
			default:
				break;
		}
		return dayOfWeek;
	}
}
